package com.toobigtofail.shapes
{
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2Fixture;
	
	import fabulaexmachina.box2fp.Box2DEntity;
	import fabulaexmachina.box2fp.Box2DShapeBuilder;
	import fabulaexmachina.box2fp.Box2DWorld;
	
	import net.flashpunk.FP;
	
	public class Line extends Box2DEntity implements IShape
	{
		public static const BEGINNING:uint = 0;
		public static const END:uint = 1;
		
		private var _savedOptions:Object;
		
		public function Line(x:Number, y:Number, verts:Array, b2Type:int=0, group:int=0, category:int=0, collmask:int=0, friction:Number=0.3, density:Number=1, restitution:Number=0.3)
		{			
			_savedOptions = {group: group, 
				             category: category, 
							 collmask: collmask, 
							 friction: friction, 
							 density: density, 
							 restitution: restitution,
						     b2Type: b2Type,
							 verts: verts};
			
			super(x, y, 0, 0, b2Type, group, category, collmask, friction, density, restitution);
		}
		
		override public function buildShapes(friction:Number, 
									density:Number, restitution:Number,
									group:int, category:int, collmask:int):void {
			buildShape(body);
		}
		
		public function buildShape(body:b2Body):void {
			var verts:Array = _savedOptions.verts;
			for (var i:int = 0; i < verts.length-1; i++) {
				var lineSegment:Array = new Array;
				lineSegment.push(verts[i], verts[i+1]);
				Box2DShapeBuilder.buildPolygon(body, lineSegment, _savedOptions.friction, _savedOptions.density, _savedOptions.restitution, _savedOptions.group, _savedOptions.category, _savedOptions.collmask);
			}			
		}
		
		public function addSegment(body:b2Body, p:b2Vec2, position:uint = END):b2Fixture {
			var verts:Array = _savedOptions.verts;
			var lineSegment:Array = new Array;
			if (position == BEGINNING) {
				lineSegment.push(p, verts[0]);
				verts.unshift(p);
			}
			else {
				lineSegment.push(verts[verts.length-1], p);
				verts.push(p);
			}
			Box2DShapeBuilder.buildPolygon(body, lineSegment, _savedOptions.friction, _savedOptions.density, _savedOptions.restitution, _savedOptions.group, _savedOptions.category, _savedOptions.collmask);
			return body.GetFixtureList();
		}
		
		public function removeSegment(body:b2Body, index:uint):void {
			var verts:Array = _savedOptions.verts;
			if (index >= verts.length || index < 0) return;
			
			verts.splice(index,1);
			var fIdx:uint = verts.length-index;
			var i:uint = 0;
			// Box2D gives us the last fixture added rather than the first,
			// so we have to traverse to the end of the linked list to get the
			// top line segment
			var f:b2Fixture = body.GetFixtureList();
			while(f && f.GetNext() && i < fIdx) {
				f = f.GetNext();
				i++
			}
			if (f) body.DestroyFixture(f);			
		}
		
		public function get b2Type():int { return _savedOptions.b2Type; }
		public function get vertices():Array { return _savedOptions.verts; } 
		
		public static function absoluteToRelative(origX:Number, origY:Number, verts:Array):Array {
			var newVerts:Array = new Array;
			for each (var v:b2Vec2 in verts) {
				newVerts.push(absoluteToRelativeVec(origX, origY, v));
			}
			return newVerts;
		}
		
		public static function absoluteToRelativeVec(origX:Number, origY:Number, p:b2Vec2):b2Vec2 {
			var origin:b2Vec2 = new b2Vec2(origX,origY);
			var newV:b2Vec2 = p.Copy();
			//trace("("+newV.x+", "+newV.y+")");
			newV.Subtract(origin);
			newV.Multiply(1/(FP.world as Box2DWorld).scale);
			return newV;
		}
		
		public static function relativeToAbsolute(origX:Number, origY:Number, verts:Array):Array {
			var newVerts:Array = new Array;
			for each (var v:b2Vec2 in verts) {
				newVerts.push(relativeToAbsoluteVec(origX, origY, v));
			}
			return newVerts;
		}
		
		public static function relativeToAbsoluteVec(origX:Number, origY:Number, p:b2Vec2):b2Vec2 {
			var origin:b2Vec2 = new b2Vec2(origX,origY);
			var newV:b2Vec2 = p.Copy();
			newV.Multiply((FP.world as Box2DWorld).scale);
			newV.Add(origin);
			
			return newV;
		}
	}
}